package org.cy.evolution.net.http;

import org.cy.evolution.BuildConfig;
import org.cy.evolution.net.http.converter.ConverterType;
import org.cy.evolution.net.http.converter.json.FastJsonConvertFactory;
import org.cy.evolution.net.http.converter.string.StringConvertFactory;
import org.cy.evolution.net.http.interceptor.HttpCommonInterceptor;

import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Converter;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

public class RetrofitManager {

    private static final Long CONNECT_TIMEOUT = 30L;
    private static final Long READ_TIMEOUT = 30L;
    private static final Long WRITE_TIMEOUT = 30L;
    private static RetrofitManager INSTANCE = null;

    private Retrofit retrofit;

    private RetrofitManager() {
    }

    private static RetrofitManager get() {
        if (null == INSTANCE) {
            synchronized (RetrofitManager.class) {
                if (null == INSTANCE) {
                    INSTANCE = new RetrofitManager();
                }
            }
        }
        return INSTANCE;
    }

    public <S> S create(Class<S> clazz) {
        return getRetrofit().create(clazz);
    }

    public Retrofit getRetrofit() {
        return retrofit;
    }

    public void setRetrofit(Retrofit retrofit) {
        this.retrofit = retrofit;
    }

    public static class Builder {

        RetrofitManager retrofitManager = new RetrofitManager();
        HttpCommonInterceptor.Builder hciBuilder = new HttpCommonInterceptor.Builder();
        private long connectTimeout = CONNECT_TIMEOUT;
        private long readTimeout = READ_TIMEOUT;
        private long writeTimeout = WRITE_TIMEOUT;
        private String baseUrl;
        private ConverterType converterType = ConverterType.STRING;

        public Builder baseUrl(String baseUrl) {
            this.baseUrl = baseUrl;
            return this;
        }

        public Builder connectTimeout(long timeout) {
            this.connectTimeout = timeout;
            return this;
        }

        public Builder readTimeout(long timeout) {
            this.readTimeout = timeout;
            return this;
        }

        public Builder writeTimeout(long timeout) {
            this.writeTimeout = timeout;
            return this;
        }

        public Builder addHeader(String header) {
            hciBuilder.addHeaderLine(header);
            return this;
        }

        public Builder addHeader(String key, String value) {
            hciBuilder.addHeaderParams(key, value);
            return this;
        }

        public Builder addHeader(String key, Integer value) {
            hciBuilder.addHeaderParams(key, value);
            return this;
        }

        public Builder addHeader(String key, Long value) {
            hciBuilder.addHeaderParams(key, value);
            return this;
        }

        public Builder addHeader(String key, Float value) {
            hciBuilder.addHeaderParams(key, value);
            return this;
        }

        public Builder addHeader(String key, Double value) {
            hciBuilder.addHeaderParams(key, value);
            return this;
        }

        public Builder converterType(ConverterType converterType) {
            this.converterType = converterType;
            return this;
        }

        public RetrofitManager build() {
            OkHttpClient client = new OkHttpClient().newBuilder()
                    .connectTimeout(connectTimeout, TimeUnit.SECONDS)
                    .readTimeout(readTimeout, TimeUnit.SECONDS)
                    .writeTimeout(writeTimeout, TimeUnit.SECONDS)
                    .addInterceptor(new HttpLoggingInterceptor().setLevel(
                            BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY
                                    : HttpLoggingInterceptor.Level.NONE
                    ))
                    .addNetworkInterceptor(hciBuilder.build())
                    .build();

            Converter.Factory convertFactory = StringConvertFactory.create();
            if (converterType == ConverterType.JSON) {
                convertFactory = FastJsonConvertFactory.create();
            }
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(this.baseUrl)
                    .addConverterFactory(convertFactory)
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .client(client)
                    .build();
            retrofitManager.setRetrofit(retrofit);
            return retrofitManager;
        }
    }
}
